/**
  ******************************************************************************
  * @file    uart_handler.c
  * @author  ashuai0110
  * @version V2.3
  * @date    2024-07-01
  * @brief   串口管理(使用帧间隔分帧或现有的分帧方法)
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2023-10-27    ashuai0110    完成基本内容
  * 2023-12-29    ashuai0110    修改从组件计时节拍接口获取时基,修改使用ring_buffer组件
  * 2024-03-03    ashuai0110    修改帧间隔时间为用户自定义参数
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "uart_handler.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup uart_handler uart_handler
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup uart_handler_local_macros uart handler local macros
 * @{
 */

/**
 * @defgroup uart_handler_check_parameters_validity uart handler check parameters validity
 * @{
 */
/* 串口管理序号有效性检查 */
#define IS_VALID_CH(x)                                                        \
(       ((x) == 0)                     ||                                     \
        ((x) > 0)                      &&                                     \
        ((x) < UART_HANDLER_NUM))
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
/**
 * @defgroup uart_handler_local_variables uart handler local variables
 * @{
 */

static uart_handler_t uartHandlerArr[UART_HANDLER_NUM]; /*!< 串口管理数组 */

/**
 * @}
 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup uart_handler_global_functions uart handler global functions
 * @{
 */

/**
  * @brief  串口管理初始化
  *
  * @param  ch        : 串口管理序号(即数组索引)
  *
  * @param  txBuf     : 串口发送缓冲区
  *
  * @param  txLen     : 串口发送缓冲区大小
  *
  * @param  rxBuf     : 串口接收缓冲区
  *
  * @param  rxLen     : 串口接收缓冲区大小
  *
  * @param  txEnFn    : 串口发送前准备函数
  *
  * @param  frameIntv : 帧间隔超时时间ms,填0则帧间隔超时时间为0
  *
  * @param  timeout   : 接收超时时间ms(无需求可忽略)
  *
  * @retval None
  */
void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint16_t frameIntv, uint16_t timeout)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(txBuf));
    ASSERT_PARAM(IS_VALID_POINT(rxBuf));
    ASSERT_PARAM(IS_VALID_POINT(txEnFn));
    
    /* 收发的环形缓冲区初始化 */
    ring_buffer_init(&uartHandlerArr[ch].txRingBuffer, txBuf, txLen);
    ring_buffer_init(&uartHandlerArr[ch].rxRingBuffer, rxBuf, rxLen);
    /* 初始化各参数 */
    uartHandlerArr[ch].uartTxEnFn = txEnFn;
    uartHandlerArr[ch].targetFrameIntv = frameIntv;
    uartHandlerArr[ch].recTimeout = timeout;
}

/**
  * @brief  串口管理轮询处理
  *
  * @param  ch          : 串口管理序号(即数组索引)
  *
  * @retval uint8_t
  *    @arg RET_OK      : 接收完成
  *    @arg RET_ERR     : 接收未完成
  *    @arg RET_TIMEOUT : 接收超时(无需求可忽略)
  */
uint8_t uart_hr_poll(uint8_t ch)
{
    uint32_t tickTmp;

    ASSERT_PARAM(IS_VALID_CH(ch));
    
    tickTmp = uartHandlerArr[ch].curFrameIntv;
    /* 帧间隔判断 */
    if(tickTmp && (module_tick_get() - tickTmp) > uartHandlerArr[ch].targetFrameIntv)
    {
        /* 置零帧间隔计数 */
        uartHandlerArr[ch].curFrameIntv = 0;
        
        return RET_OK;
    }
    tickTmp = uartHandlerArr[ch].recTimeoutCnt;
    /* 接收超时判断 */
    if(tickTmp && (module_tick_get() - tickTmp) > uartHandlerArr[ch].recTimeout)
    {
        uartHandlerArr[ch].recTimeoutCnt = 0; /* 置零接收超时 */
        
        return RET_TIMEOUT;
    }
    
    return RET_ERR;
}

/**
  * @brief  读出数据从串口接收缓冲区
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据存储区
  *
  * @param  len  : 读出长度byte
  *
  * @retval 实际读出的长度
  */
uint32_t uart_hr_read_rx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    /* 从环形缓冲区读出数据 */
    len = ring_buffer_read(&uartHandlerArr[ch].rxRingBuffer, pBuf, len);
    
    return len;
}

/**
  * @brief  写入数据到串口接收缓冲区
  *
  * @note   一般加入到串口接收中断
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据缓存区
  *
  * @param  len  : 写入长度byte
  *
  * @retval 实际写入的长度
  */
uint32_t uart_hr_write_rx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    /* 向环形缓冲区写入数据 */
    len = ring_buffer_write(&uartHandlerArr[ch].rxRingBuffer, pBuf, len);
    /* 若实际写入长度不为0则开启帧间隔计数 */
    if(0 < len)
    {
        uartHandlerArr[ch].curFrameIntv = module_tick_get(); /* 开启帧间隔超时计数 */
        uartHandlerArr[ch].recTimeoutCnt = 0; /* 关闭接收超时计数 */
    }
    
    return len;
}

/**
  * @brief  读出数据从串口发送缓冲区
  *
  * @note   一般加入到串口发送中断
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据存储区
  *
  * @param  len  : 读出长度byte
  *
  * @retval 实际读出的长度
  */
uint32_t uart_hr_read_tx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    /* 从环形缓冲区读出数据 */
    len = ring_buffer_read(&uartHandlerArr[ch].txRingBuffer, pBuf, len);;
    /* 若实际读出长度为0则关闭发送并开启接收超时计数 */
    if(0 == len)
    {
        uartHandlerArr[ch].uartTxEnFn(0);
        uartHandlerArr[ch].recTimeoutCnt = module_tick_get();
    }
    
    return len;
}

/**
  * @brief  写入数据到串口发送缓冲区
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据缓存区
  *
  * @param  len  : 写入长度byte
  *
  * @retval 实际写入的长度
  */
uint32_t uart_hr_write_tx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    /* 向环形缓冲区写入数据 */
    len = ring_buffer_write(&uartHandlerArr[ch].txRingBuffer, pBuf, len);
    /* 若实际写入长度不为0则开启发送 */
    if(len) { uartHandlerArr[ch].uartTxEnFn(1); }
    
    return len;
}

/**
  * @brief  设置串口管理帧间隔超时时间ms
  *
  * @param  ch        : 串口管理序号(即数组索引)
  *
  * @param  frameIntv : 帧间隔超时时间ms,填0则帧间隔超时时间为0
  *
  * @retval None
  */
void uart_hr_set_frame_intv(uint8_t ch, uint16_t frameIntv)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    
    uartHandlerArr[ch].targetFrameIntv = frameIntv;
}

/**
  * @brief  获取串口管理帧间隔超时时间ms
  *
  * @param  ch : 串口管理序号(即数组索引)
  *
  * @retval 帧间隔超时时间ms
  */
uint16_t uart_hr_get_frame_intv(uint8_t ch)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    
    return uartHandlerArr[ch].targetFrameIntv;
}

/**
  * @brief  设置串口管理接收超时时间ms
  *
  * @param  ch      : 串口管理序号(即数组索引)
  *
  * @param  timeout : 接收超时时间ms
  *
  * @retval None
  */
void uart_hr_set_rec_timeout(uint8_t ch, uint16_t timeout)
{
    uartHandlerArr[ch].recTimeout = timeout;
}

/**
  * @brief  获取串口管理接收超时时间ms
  *
  * @param  ch : 串口管理序号(即数组索引)
  *
  * @retval 串口管理接收超时时间ms
  */
uint16_t uart_hr_get_rec_timeout(uint8_t ch)
{
    return uartHandlerArr[ch].recTimeout;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
